﻿using HMEngine.HMCameras;
using HMEngine.HMEffects;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Content;
using Microsoft.Xna.Framework.Graphics;

namespace HMEngine.HMObjects {
    public class HMModel : HMObject {
        private readonly string myAsset;
        private Model myModel;

        public Vector3 AmbientColor { get; set; }
        public Vector3 DiffuseColor { get; set; }
        public float SpecularPower { get; set; }

        public HMModel(string asset) {
            myAsset = asset;
            Scaling = new Vector3(1);

            AmbientColor = new Vector3(0.15f);
            DiffuseColor = new Vector3(0.25f);
            SpecularPower = 8;
        }

        internal void SetMaterialProperties() {
            Effect effect = HMEffectManager.ActiveShader.Effect;

            if (null != effect.Parameters["AmbientColor"]) {
                effect.Parameters["AmbientColor"].SetValue(AmbientColor);
            }
            if (null != effect.Parameters["DiffuseColor"]) {
                effect.Parameters["DiffuseColor"].SetValue(DiffuseColor);
            }
            if (null != effect.Parameters["SpecularPower"]) {
                effect.Parameters["SpecularPower"].SetValue(SpecularPower);
            }

            effect.CommitChanges();
        }

        public override void LoadContent(GraphicsDevice myDevice, ContentManager myLoader) { myModel = myLoader.Load<Model>(myAsset); }

        public override void Render(GraphicsDevice myDevice) {
            Matrix World =
                HMCameraManager.ActiveCamera.World *
                Matrix.CreateScale(Scaling) *
                Matrix.CreateFromQuaternion(Rotation) *
                Matrix.CreateTranslation(Position);

            foreach (ModelMesh mesh in myModel.Meshes) {
                myDevice.Indices = mesh.IndexBuffer;

                if (null != HMEffectManager.ActiveShader.Effect.Parameters["World"]) {
                    HMEffectManager.ActiveShader.Effect.Parameters["World"].SetValue(World * mesh.ParentBone.Transform);
                }
                HMEffectManager.ActiveShader.Effect.CommitChanges();

                // Each mesh is made of parts (grouped by texture, etc.)
                foreach (ModelMeshPart part in mesh.MeshParts) {
                    // Change the device settings for each part to be rendered
                    myDevice.VertexDeclaration = part.VertexDeclaration;
                    myDevice.Vertices[0].SetSource(
                        mesh.VertexBuffer,
                        part.StreamOffset,
                        part.VertexStride
                        );

                    // Make sure we use the texture for the current part also
                    myDevice.Textures[0] = ((BasicEffect)part.Effect).Texture;

                    // Set up the shader properties for this mesh part
                    SetMaterialProperties();

                    // Finally draw the actual triangles on the screen
                    myDevice.DrawIndexedPrimitives(
                        PrimitiveType.TriangleList,
                        part.BaseVertex,
                        0,
                        part.NumVertices,
                        part.StartIndex,
                        part.PrimitiveCount
                        );
                }
            }
        }

        public override void UnloadContent() { }
    }
}